package initialize

import (
	"go.uber.org/zap"
	"gorm.io/driver/mysql"
	"gorm.io/driver/postgres"
	"gorm.io/driver/sqlite"
	"gorm.io/driver/sqlserver"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"os"
	"perfect-vue-admin/global"
	"perfect-vue-admin/model"
)

// Gorm 初始化数据库并产生数据库全局变量
func InitGormDB() *gorm.DB {
	switch global.CONFIG.System.DbType {
	case "mysql":
		return InitGormMysql()
	case "postgresql":
		return InitGormPostgreSql()
	case "sqlite": // sqlite需要gcc支持 windows用户需要自行安装gcc 如需使用打开注释即可
		return InitGormSqlite()
	case "sqlserver":
		return InitGormSqlServer()
	default:
		return InitGormMysql()
	}
}

// 注册数据库表专用
func MigrateDBTables(db *gorm.DB) {
	err := db.AutoMigrate(
		model.SysUser{},
		model.SysAuthority{},
		model.SysApi{},
		model.SysBaseMenu{},
		model.SysBaseMenuParameter{},
		model.JwtBlacklist{},
		model.SysWorkflow{},
		model.SysWorkflowStepInfo{},
		model.SysDictionary{},
		model.SysDictionaryDetail{},
		model.SysFile{},
		model.ExaFileUploadAndDownload{},
		model.ExaFile{},
		model.ExaFileChunk{},
		model.ExaSimpleUploader{},
		model.ExaCustomer{},
		model.SysOperationRecord{},
	)
	if err != nil {
		global.LOG.Error("register table failed", zap.Any("err", err))
		os.Exit(0)
	}
	global.LOG.Info("register table success")
}

// 初始化数据库并产生数据库全局变量
func InitGormMysql() *gorm.DB {
	admin := global.CONFIG.Mysql
	mysqlConfig := mysql.Config{
		DSN:                       admin.Username + ":" + admin.Password + "@(" + admin.Path + ")/" + admin.Dbname + "?" + admin.Config, // DSN data source name
		DefaultStringSize:         191,                                                                                                  // string 类型字段的默认长度
		DisableDatetimePrecision:  true,                                                                                                 // 禁用 datetime 精度，MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,                                                                                                 // 重命名索引时采用删除并新建的方式，MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,                                                                                                 // 用 `change` 重命名列，MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false,                                                                                                // 根据版本自动配置
	}
	gormConfig := Gormconfig(admin.LogMode)
	if db, err := gorm.Open(mysql.New(mysqlConfig), gormConfig); err != nil {
		global.LOG.Error("MySQL启动异常", zap.Any("err", err))
		os.Exit(0)
		return nil
	} else {
		MigrateDBTables(db)
		sqlDB, _ := db.DB()
		sqlDB.SetMaxIdleConns(admin.MaxIdleConns)
		sqlDB.SetMaxOpenConns(admin.MaxOpenConns)
		return db
	}
}

// GormPostgreSql 初始化PostgreSql数据库
func InitGormPostgreSql() *gorm.DB {
	p := global.CONFIG.Postgresql
	dsn := "user=" + p.Username + " password=" + p.Password + " dbname=" + p.Dbname + " port=" + p.Port + " " + p.Config
	postgresConfig := postgres.Config{
		DSN:                  dsn,                    // DSN data source name
		PreferSimpleProtocol: p.PreferSimpleProtocol, // 禁用隐式 prepared statement
	}
	gormConfig := Gormconfig(p.Logger)
	if db, err := gorm.Open(postgres.New(postgresConfig), gormConfig); err != nil {
		global.LOG.Error("PostgreSql启动异常", zap.Any("err", err))
		os.Exit(0)
		return nil
	} else {
		MigrateDBTables(db)
		sqlDB, _ := db.DB()
		sqlDB.SetMaxIdleConns(p.MaxIdleConns)
		sqlDB.SetMaxOpenConns(p.MaxOpenConns)
		return db
	}
}

//GormSqlite 初始化Sqlite数据库 sqlite需要gcc支持 windows用户需要自行安装gcc 如需使用打开注释即可
func InitGormSqlite() *gorm.DB {
	s := global.CONFIG.Sqlite
	gormConfig := Gormconfig(s.Logger)
	if db, err := gorm.Open(sqlite.Open(s.Path), gormConfig); err != nil {
		global.LOG.Error("Sqlite启动异常", zap.Any("err", err))
		os.Exit(0)
		return nil
	} else {
		MigrateDBTables(db)
		sqlDB, _ := db.DB()
		sqlDB.SetMaxIdleConns(s.MaxIdleConns)
		sqlDB.SetMaxOpenConns(s.MaxOpenConns)
		return db
	}
}

// GormSqlServer 初始化SqlServer数据库
func InitGormSqlServer() *gorm.DB {
	ss := global.CONFIG.Sqlserver
	dsn := "sqlserver://" + ss.Username + ":" + ss.Password + "@" + ss.Path + "?database=gorm"
	if db, err := gorm.Open(sqlserver.Open(dsn), &gorm.Config{}); err != nil {
		global.LOG.Error("SqlServer启动异常", zap.Any("err", err))
		os.Exit(0)
		return nil
	} else {
		MigrateDBTables(db)
		sqlDB, _ := db.DB()
		sqlDB.SetMaxIdleConns(ss.MaxIdleConns)
		sqlDB.SetMaxOpenConns(ss.MaxOpenConns)
		return db
	}
}

// config 根据配置决定是否开启日志
func Gormconfig(mod bool) (c *gorm.Config) {
	if mod {
		c = &gorm.Config{
			Logger:                                   logger.Default.LogMode(logger.Info),
			DisableForeignKeyConstraintWhenMigrating: true,
		}
	} else {
		c = &gorm.Config{
			Logger:                                   logger.Default.LogMode(logger.Silent),
			DisableForeignKeyConstraintWhenMigrating: true,
		}
	}
	return
}
